/**
 * 
 */
package org.statewalker.validator.grammar.xhtml;

import org.statewalker.validator.AbstractGrammar;
import org.statewalker.validator.AbstractValidator;
import org.statewalker.validator.IParseKey;

/**
 * http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd
 * 
 * @author kotelnikov
 */
public class XHTMLGrammar extends AbstractGrammar {

    public final IParseKey S_A = newKey("a");

    public final IParseKey S_ABBR = newKey("abbr");

    public final IParseKey S_ACRONYM = newKey("acronym");

    public final IParseKey S_ADDRESS = newKey("address");

    public final IParseKey S_AREA = newKey("area");

    public final IParseKey S_B = newKey("b");

    public final IParseKey S_BASE = newKey("base");

    public final IParseKey S_BDO = newKey("bdo");

    public final IParseKey S_BIG = newKey("big");

    public final IParseKey S_BLOCKQUOTE = newKey("blockquote");

    public final IParseKey S_BODY = newKey("body");

    public final IParseKey S_BR = newKey("br");

    public final IParseKey S_BUTTON = newKey("button");

    public final IParseKey S_CAPTION = newKey("caption");

    public final IParseKey S_CDATA = newKey("CDATA");

    public final IParseKey S_CITE = newKey("cite");

    public final IParseKey S_CODE = newKey("code");

    public final IParseKey S_COL = newKey("col");

    public final IParseKey S_COLGROUP = newKey("colgroup");

    public final IParseKey S_DD = newKey("dd");

    public final IParseKey S_DEL = newKey("del");

    public final IParseKey S_DFN = newKey("dfn");

    public final IParseKey S_DIV = newKey("div");

    public final IParseKey S_DL = newKey("dl");

    public final IParseKey S_DT = newKey("dt");

    public final IParseKey S_EM = newKey("em");

    public final IParseKey S_FIELDSET = newKey("fieldset");

    public final IParseKey S_FORM = newKey("form");

    public final IParseKey S_H1 = newKey("h1");

    public final IParseKey S_H2 = newKey("h2");

    public final IParseKey S_H3 = newKey("h3");

    public final IParseKey S_H4 = newKey("h4");

    public final IParseKey S_H5 = newKey("h5");

    public final IParseKey S_H6 = newKey("h6");

    public final IParseKey S_HEAD = newKey("head");

    public final IParseKey S_HR = newKey("hr");

    public final IParseKey S_HTML = newKey("html");

    public final IParseKey S_I = newKey("i");

    public final IParseKey S_IMG = newKey("img");

    public final IParseKey S_INPUT = newKey("input");

    public final IParseKey S_INS = newKey("ins");

    public final IParseKey S_KBD = newKey("kbd");

    public final IParseKey S_LABEL = newKey("label");

    public final IParseKey S_LEGEND = newKey("legend");

    public final IParseKey S_LI = newKey("li");

    public final IParseKey S_LINK = newKey("link");

    public final IParseKey S_MAP = newKey("map");

    public final IParseKey S_META = newKey("meta");

    public final IParseKey S_NOSCRIPT = newKey("noscript");

    public final IParseKey S_OBJECT = newKey("object");

    public final IParseKey S_OL = newKey("ol");

    public final IParseKey S_OPTGROUP = newKey("optgroup");

    public final IParseKey S_OPTION = newKey("option");

    public final IParseKey S_P = newKey("p");

    public final IParseKey S_PARAM = newKey("param");

    public final IParseKey S_PCDATA = newKey("#PCDATA");

    public final IParseKey S_PRE = newKey("pre");

    public final IParseKey S_Q = newKey("q");

    public final IParseKey S_SAMP = newKey("samp");

    public final IParseKey S_SCRIPT = newKey("script");

    public final IParseKey S_SELECT = newKey("select");

    public final IParseKey S_SMALL = newKey("small");

    public final IParseKey S_SPAN = newKey("span");

    public final IParseKey S_STRONG = newKey("strong");

    public final IParseKey S_STYLE = newKey("style");

    public final IParseKey S_SUB = newKey("sub");

    public final IParseKey S_SUP = newKey("sup");

    public final IParseKey S_TABLE = newKey("table");

    public final IParseKey S_TBODY = newKey("tbody");

    public final IParseKey S_TD = newKey("td");

    public final IParseKey S_TEXTAREA = newKey("textarea");

    public final IParseKey S_TFOOT = newKey("tfoot");

    public final IParseKey S_TH = newKey("th");

    public final IParseKey S_THEAD = newKey("thead");

    public final IParseKey S_TITLE = newKey("title");

    public final IParseKey S_TR = newKey("tr");

    public final IParseKey S_TT = newKey("tt");

    public final IParseKey S_UL = newKey("ul");

    public final IParseKey S_VAR = newKey("var");

    public XHTMLGrammar(AbstractValidator<?, ?> validator) {
        super(validator);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_block
    // <!ENTITY % block
    // "p | %heading; | div | %lists; | %blocktext; | fieldset | table">
    private void addBlock(IParseKey key) {
        defineSubstates(key, S_P, S_DIV, S_FIELDSET, S_TABLE);
        addHeading(key);
        addLists(key);
        addBlocktext(key);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_Block
    // <!ENTITY % Block "(%block; | form | %misc;)*">
    private void addBlockExtended(IParseKey key) {
        addBlock(key);
        defineSubstates(key, S_FORM);
        addMisc(key);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_blocktext
    // <!ENTITY % blocktext "pre | hr | blockquote | address">
    private void addBlocktext(IParseKey key) {
        defineSubstates(key, S_PRE, S_HR, S_BLOCKQUOTE, S_ADDRESS);
    }

    // 
    private void addCDATA(IParseKey key) {
        defineSubstates(key, S_CDATA);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_Flow
    // <!ENTITY % Flow "(#PCDATA | %block; | form | %inline; | %misc;)*">
    private void addFlow(IParseKey key) {
        defineSubstates(key, S_FORM);
        addPCDATA(key);
        addBlock(key);
        addInline(key);
        addMisc(key);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_fontstyle
    // <!ENTITY % fontstyle "tt | i | b | big | small ">
    private void addFontstyle(IParseKey key) {
        defineSubstates(key, S_TT, S_I, S_B, S_BIG, S_SMALL);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_heading
    // <!ENTITY % heading "h1|h2|h3|h4|h5|h6">
    private void addHeading(IParseKey key) {
        defineSubstates(key, S_H1, S_H2, S_H3, S_H4, S_H5, S_H6);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_inline
    // <!ENTITY % inline
    // "a | %special; | %fontstyle; | %phrase; | %inline.forms;">
    private void addInline(IParseKey key) {
        defineSubstates(key, S_A);
        addSpecial(key);
        addFontstyle(key);
        addPhrase(key);
        addInlineForms(key);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_Inline
    // <!ENTITY % Inline "(#PCDATA | %inline; | %misc.inline;)*">
    private void addInlineExtended(IParseKey key) {
        addPCDATA(key);
        addInline(key);
        addMiscInline(key);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_inline.forms
    // <!ENTITY % inline.forms "input | select | textarea | label | button">
    private void addInlineForms(IParseKey key) {
        defineSubstates(key, S_INPUT, S_SELECT, S_TEXTAREA, S_LABEL, S_BUTTON);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_lists
    // <!ENTITY % lists "ul | ol | dl">
    private void addLists(IParseKey key) {
        defineSubstates(key, S_UL, S_OL, S_DL);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_misc
    // <!ENTITY % misc "noscript | %misc.inline;">
    private void addMisc(IParseKey key) {
        defineSubstates(key, S_NOSCRIPT);
        addMiscInline(key);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_misc.inline
    // <!ENTITY % misc.inline "ins | del | script">
    private void addMiscInline(IParseKey key) {
        defineSubstates(key, S_INS, S_DEL, S_SCRIPT);
    }

    private void addOptions(IParseKey key) {
        IParseKey option = S_OPTION;
        defineTransition(key, getINITIAL(), option, option);
        defineTransition(key, option, option, option);
        // The field can not be empty.
        // It contains at least one option by default.
        defineTransition(key, getINITIAL(), getANY(), option);
    }

    // 
    private void addPCDATA(IParseKey key) {
        defineSubstates(key, S_PCDATA);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_phrase
    // <!ENTITY % phrase
    // "em | strong | dfn | code | q | samp | kbd | var | cite | abbr | acronym | sub | sup ">
    private void addPhrase(IParseKey key) {
        defineSubstates(
            key,
            S_EM,
            S_STRONG,
            S_DFN,
            S_CODE,
            S_Q,
            S_SAMP,
            S_KBD,
            S_VAR,
            S_CITE,
            S_ABBR,
            S_ACRONYM,
            S_SUB,
            S_SUP);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_special
    // <!ENTITY % special "%special.pre; | object | img ">
    private void addSpecial(IParseKey key) {
        addSpecialPre(key);
        defineSubstates(key, S_OBJECT, S_IMG);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_special.pre
    // <!ENTITY % special.pre "br | span | bdo | map">
    private void addSpecialPre(IParseKey key) {
        defineSubstates(key, S_BR, S_SPAN, S_BDO, S_MAP);
    }

    protected IParseKey getBlockContainer() {
        return S_BODY;
    }

    private IParseKey getDefaultFormElementContainer() {
        return S_P;
    }

    @Override
    public void init() {
        initA();
        initABBR();
        initACRONYM();
        initADDRESS();
        initAREA();
        initB();
        initBASE();
        initBDO();
        initBIG();
        initBLOCKQUOTE();
        initBODY();
        initBR();
        initBUTTON();
        initCAPTION();
        initCDATA();
        initCITE();
        initCODE();
        initCOL();
        initCOLGROUP();
        initDD();
        initDEL();
        initDFN();
        initDIV();
        initDL();
        initDT();
        initEM();
        initFIELDSET();
        initFORM();
        initH1();
        initH2();
        initH3();
        initH4();
        initH5();
        initH6();
        initHEAD();
        initHR();
        initHTML();
        initI();
        initIMG();
        initINPUT();
        initINS();
        initKBD();
        initLABEL();
        initLEGEND();
        initLI();
        initLINK();
        initMAP();
        initMETA();
        initNOSCRIPT();
        initOBJECT();
        initOL();
        initOPTGROUP();
        initOPTION();
        initP();
        initPARAM();
        initPCDATA();
        initPRE();
        initQ();
        initSAMP();
        initSCRIPT();
        initSELECT();
        initSMALL();
        initSPAN();
        initSTRONG();
        initSTYLE();
        initSUB();
        initSUP();
        initTABLE();
        initTBODY();
        initTD();
        initTEXTAREA();
        initTFOOT();
        initTH();
        initTHEAD();
        initTITLE();
        initTR();
        initTT();
        initUL();
        initVAR();
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_a
    // <!ELEMENT a %a.content;>
    // <!ENTITY % a.content
    // "(#PCDATA | %special; | %fontstyle; | %phrase; | %inline.forms; | %misc.inline;)*">
    protected void initA() {
        IParseKey key = S_A;
        defineParent(key, S_P);

        // Definition of the "a.content":
        addPCDATA(key);
        addSpecial(key);
        addFontstyle(key);
        addPhrase(key);
        addInlineForms(key);
        addMiscInline(key);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_abbr
    // <!ELEMENT abbr %Inline;> <!-- abbreviation -->
    protected void initABBR() {
        initPhraseItem(S_ABBR);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_acronym
    // <!ELEMENT acronym %Inline;> <!-- acronym -->
    protected void initACRONYM() {
        initPhraseItem(S_ACRONYM);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_address
    // <!ELEMENT address %Inline;>
    protected void initADDRESS() {
        defineParent(S_ADDRESS, getBlockContainer());
        addInlineExtended(S_ADDRESS);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_area
    // <!ELEMENT area EMPTY>
    protected void initAREA() {
        defineParent(S_AREA, S_MAP);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_b
    // <!ELEMENT b %Inline;> <!-- bold font -->
    protected void initB() {
        initPhraseItem(S_B);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_base
    // <!ELEMENT base EMPTY>
    protected void initBASE() {
        defineParent(S_BASE, S_HEAD);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_bdo
    // <!ELEMENT bdo %Inline;> <!-- I18N BiDi over-ride -->
    protected void initBDO() {
        initPhraseItem(S_BDO);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_big
    // <!ELEMENT big %Inline;> <!-- bigger font -->
    protected void initBIG() {
        initPhraseItem(S_BIG);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_blockquote
    // <!ELEMENT blockquote %Block;>
    protected void initBLOCKQUOTE() {
        defineParent(S_BLOCKQUOTE, getBlockContainer());
        addBlockExtended(S_BLOCKQUOTE);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_body
    // <!ELEMENT body %Block;>
    protected void initBODY() {
        defineParent(S_BODY, S_HTML);
        addBlockExtended(S_BODY);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_br
    // <!ELEMENT br EMPTY> <!-- forced line break -->
    protected void initBR() {
        defineParent(S_BR, S_P);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_button
    // <!ELEMENT button %button.content;> <!-- push button -->
    //
    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_button.content:
    // <!ENTITY % button.content
    // "(#PCDATA | p | %heading; | div | %lists; | %blocktext; |    table | %special; | %fontstyle; | %phrase; | %misc;)*">
    protected void initBUTTON() {
        IParseKey parent = getDefaultFormElementContainer();
        defineParent(S_BUTTON, parent);

        // Definition of the "button.content":
        defineSubstates(S_BUTTON, S_P, S_DIV, S_TABLE);
        addPCDATA(S_BUTTON);
        addHeading(S_BUTTON);
        addLists(S_BUTTON);
        addBlocktext(S_BUTTON);
        addSpecial(S_BUTTON);
        addFontstyle(S_BUTTON);
        addPhrase(S_BUTTON);
        addMisc(S_BUTTON);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_caption
    // <!ELEMENT caption %Inline;>
    protected void initCAPTION() {
        defineParent(S_CAPTION, S_TABLE);
        addInlineExtended(S_CAPTION);
    }

    protected void initCDATA() {
        defineParent(S_CDATA, S_P);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_cite
    // <!ELEMENT cite %Inline;> <!-- citation -->
    protected void initCITE() {
        initPhraseItem(S_CITE);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_code
    // <!ELEMENT code %Inline;> <!-- program code -->
    protected void initCODE() {
        initPhraseItem(S_CODE);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_col
    // <!ELEMENT col EMPTY>
    protected void initCOL() {
        defineParent(S_COL, S_TABLE);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_colgroup
    // <!ELEMENT colgroup (col)*>
    protected void initCOLGROUP() {
        defineParent(S_COLGROUP, S_TABLE);
        defineSubstates(S_COLGROUP, S_COL);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_dd
    // <!ELEMENT dd %Flow;>
    protected void initDD() {
        defineParent(S_DD, S_DL);
        addFlow(S_DD);
        if (useExtendedRules()) {
            defineTransition(S_DD, S_DD, getFINAL());
            defineTransition(S_DD, S_DT, getFINAL());
        }
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_del
    // <!ELEMENT del %Flow;>
    protected void initDEL() {
        defineParent(S_DEL, getBlockContainer());
        addFlow(S_DEL);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_dfn
    // <!ELEMENT dfn %Inline;> <!-- definitional -->
    protected void initDFN() {
        initPhraseItem(S_DFN);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_div
    // <!ELEMENT div %Flow;> <!-- generic language/style container -->
    protected void initDIV() {
        defineParent(S_DIV, getBlockContainer());
        addFlow(S_DIV);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_dl
    // <!ELEMENT dl (dt|dd)+>
    protected void initDL() {
        defineParent(S_DL, getBlockContainer());
        defineSubstates(S_DL, S_DD, S_DT);
        // By default (if it is not a "dd" or "dt" tag) the list should
        // create a "dd" element.
        defineMandatoryTransition(S_DL, getINITIAL(), S_DD);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_dt
    // <!ELEMENT dt %Inline;>
    protected void initDT() {
        defineParent(S_DT, S_DL);
        addInlineExtended(S_DT);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_em
    // <!ELEMENT em %Inline;> <!-- emphasis -->
    protected void initEM() {
        initPhraseItem(S_EM);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_fieldset
    // <!ELEMENT fieldset (#PCDATA | legend | %block; | form | %inline; |
    // %misc;)*>
    protected void initFIELDSET() {
        defineParent(S_FIELDSET, getBlockContainer());
        defineSubstates(S_FIELDSET, S_LEGEND, S_FORM);
        addPCDATA(S_FIELDSET);
        addBlock(S_FIELDSET);
        addInline(S_FIELDSET);
        addMisc(S_FIELDSET);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_form
    // <!ELEMENT form %form.content;> <!-- forms shouldn't be nested -->
    // <!ENTITY % form.content "(%block; | %misc;)*">
    protected void initFORM() {
        defineParent(S_FORM, getBlockContainer());
        // Definition of the "form.content":
        addBlock(S_FORM);
        addMisc(S_FORM);
    }

    protected void initH1() {
        initHN(S_H1);
    }

    protected void initH2() {
        initHN(S_H2);
    }

    protected void initH3() {
        initHN(S_H3);
    }

    protected void initH4() {
        initHN(S_H4);
    }

    protected void initH5() {
        initHN(S_H5);
    }

    protected void initH6() {
        initHN(S_H6);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_head
    // <!ELEMENT head (%head.misc;, ((title, %head.misc;, (base, %head.misc;)?)
    // | (base, %head.misc;, (title, %head.misc;))))>
    // 
    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_head.misc
    // <!ENTITY % head.misc "(script|style|meta|link|object)*">
    protected void initHEAD() {
        defineParent(S_HEAD, S_HTML);
        defineSubstates(S_HEAD, S_TITLE, S_BASE);

        // Defintion of the "head.misc":
        defineSubstates(S_HEAD, S_SCRIPT, S_STYLE, S_META, S_LINK, S_OBJECT);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_h1
    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_h2
    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_h3
    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_h4
    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_h5
    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_h6
    // <!ELEMENT h1 %Inline;>
    protected void initHN(IParseKey key) {
        defineParent(key, getBlockContainer());
        addInlineExtended(key);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_hr
    // <!ELEMENT hr EMPTY>
    protected void initHR() {
        defineParent(S_HR, getBlockContainer());
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_html
    // <!ELEMENT html (head, body)>
    protected void initHTML() {
        defineParent(S_HTML, getROOT());
        defineMandatoryTransition(S_HTML, getINITIAL(), S_HEAD);
        defineMandatoryTransition(S_HTML, S_HEAD, S_BODY);
        defineTransition(S_HTML, S_BODY, getANY(), getERROR());
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_i
    // <!ELEMENT i %Inline;> <!-- italic font -->
    protected void initI() {
        initPhraseItem(S_I);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_img
    // <!ELEMENT img EMPTY>
    protected void initIMG() {
        defineParent(S_IMG, S_P);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_input
    // <!ELEMENT input EMPTY> <!-- form control -->
    protected void initINPUT() {
        IParseKey parent = getDefaultFormElementContainer();
        defineParent(S_INPUT, parent);
        addInlineExtended(S_INPUT);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_ins
    // <!ELEMENT ins %Flow;>
    protected void initINS() {
        defineParent(S_INS, getBlockContainer());
        addFlow(S_INS);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_kbd
    // <!ELEMENT kbd %Inline;> <!-- something user would type -->
    protected void initKBD() {
        initPhraseItem(S_KBD);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_label
    // <!ELEMENT label %Inline;>
    protected void initLABEL() {
        IParseKey parent = getDefaultFormElementContainer();
        defineParent(S_LABEL, parent);
        addInlineExtended(S_LABEL);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_legend
    // <!ELEMENT legend %Inline;> <!-- fieldset label -->
    protected void initLEGEND() {
        defineParent(S_LEGEND, S_FIELDSET);
        addInlineExtended(S_LEGEND);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_li
    // <!ELEMENT li %Flow;>
    protected void initLI() {
        defineParent(S_LI, S_UL);
        addFlow(S_LI);
        if (useExtendedRules()) {
            defineTransition(S_LI, S_LI, getFINAL());
        }
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_link
    // <!ELEMENT link EMPTY>
    protected void initLINK() {
        defineParent(S_LINK, S_HEAD);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_ol
    // <!ELEMENT ol (li)+>
    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_ul
    // <!ELEMENT ul (li)+>
    private void initList(IParseKey key) {
        defineParent(key, getBlockContainer());
        defineSubstates(key, S_LI);
        defineMandatoryTransition(key, getINITIAL(), S_LI);
        if (useExtendedRules()) {
            // Open a "li" element if there is a new list
            defineTransition(key, S_UL, S_LI);
            defineTransition(key, S_OL, S_LI);
            defineTransition(key, S_DL, S_LI);
        }
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_map
    // <!ELEMENT map ((%block; | form | %misc;)+ | area+)>
    protected void initMAP() {
        defineParent(S_MAP, getBlockContainer());
        addBlock(S_MAP);
        defineSubstates(S_MAP, S_FORM, S_AREA);
        addMisc(S_MAP);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_meta
    // <!ELEMENT meta EMPTY>
    protected void initMETA() {
        defineParent(S_META, S_HEAD);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_noscript
    // <!ELEMENT noscript %Block;>
    protected void initNOSCRIPT() {
        defineParent(S_NOSCRIPT, getBlockContainer());
        addBlockExtended(S_NOSCRIPT);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_object
    // <!ELEMENT object (#PCDATA | param | %block; | form | %inline; | %misc;)*>
    protected void initOBJECT() {
        defineParent(S_OBJECT, getBlockContainer());
        defineSubstates(S_OBJECT, S_PARAM, S_FORM);
        addPCDATA(S_OBJECT);
        addBlock(S_OBJECT);
        addInline(S_OBJECT);
        addMisc(S_OBJECT);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_ol
    // <!ELEMENT ul (li)+>
    protected void initOL() {
        initList(S_OL);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_optgroup
    // <!ELEMENT optgroup (option)+> <!-- option group -->
    protected void initOPTGROUP() {
        defineParent(S_OPTGROUP, S_SELECT);
        addOptions(S_OPTGROUP);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_option
    // <!ELEMENT option (#PCDATA)> <!-- selectable choice -->
    protected void initOPTION() {
        defineParent(S_OPTION, S_SELECT);
        addPCDATA(S_OPTION);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_p
    // <!ELEMENT p %Inline;>
    protected void initP() {
        defineParent(S_P, getBlockContainer());
        addInlineExtended(S_P);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_param
    // <!ELEMENT param EMPTY>
    protected void initPARAM() {
        defineParent(S_PARAM, S_OBJECT);
    }

    protected void initPCDATA() {
        defineParent(S_PCDATA, S_P);
    }

    private void initPhraseItem(IParseKey key) {
        defineParent(key, S_P);
        addInlineExtended(key);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_pre
    // <!ELEMENT pre %pre.content;>
    // <!ENTITY % pre.content
    // "(#PCDATA | a | %fontstyle; | %phrase; | %special.pre; | %misc.inline; | %inline.forms;)*">
    protected void initPRE() {
        defineParent(S_PRE, getBlockContainer());

        // The definition of the "pre.content":
        // <!ENTITY % pre.content
        // "(#PCDATA | a | %fontstyle; | %phrase; | %special.pre; | %misc.inline; | %inline.forms;)*">
        defineSubstates(S_PRE, S_A);
        addFontstyle(S_PRE);
        addPhrase(S_PRE);
        addSpecialPre(S_PRE);
        addMiscInline(S_PRE);
        addInlineForms(S_PRE);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_q
    // <!ELEMENT q %Inline;> <!-- inlined quote -->
    protected void initQ() {
        initPhraseItem(S_Q);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_samp
    // <!ELEMENT samp %Inline;> <!-- sample -->
    protected void initSAMP() {
        initPhraseItem(S_SAMP);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_script
    // <!ENTITY % Script "CDATA">
    protected void initSCRIPT() {
        defineParent(S_SCRIPT, S_P);
        addCDATA(S_SCRIPT);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_select
    // <!ELEMENT select (optgroup|option)+> <!-- option selector -->
    protected void initSELECT() {
        IParseKey parent = getDefaultFormElementContainer();
        defineParent(S_SELECT, parent);
        defineTransition(S_SELECT, getINITIAL(), S_OPTGROUP, S_OPTGROUP);
        defineTransition(S_SELECT, S_OPTGROUP, S_OPTGROUP, S_OPTGROUP);
        // This method defines "option" elements.
        addOptions(S_SELECT);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_small
    // <!ELEMENT small %Inline;> <!-- smaller font -->
    protected void initSMALL() {
        initPhraseItem(S_SMALL);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_span
    // <!ELEMENT span %Inline;> <!-- generic language/style container -->
    protected void initSPAN() {
        initPhraseItem(S_SPAN);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_strong
    // <!ELEMENT strong %Inline;> <!-- strong emphasis -->
    protected void initSTRONG() {
        initPhraseItem(S_STRONG);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_style
    // <!ELEMENT title (#PCDATA)>
    protected void initSTYLE() {
        defineParent(S_STYLE, S_HEAD);
        addPCDATA(S_STYLE);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_sub
    // <!ELEMENT sub %Inline;> <!-- subscript -->
    protected void initSUB() {
        initPhraseItem(S_SUB);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_sup
    // <!ELEMENT sup %Inline;> <!-- superscript -->
    protected void initSUP() {
        initPhraseItem(S_SUP);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_table
    // <!ELEMENT table (caption?, (col*|colgroup*), thead?, tfoot?,
    // (tbody+|tr+))>
    protected void initTABLE() {
        defineParent(S_TABLE, getBlockContainer());

        IParseKey initial = getINITIAL();
        // Transitions from the initial state
        defineTransition(S_TABLE, initial, S_CAPTION, S_CAPTION);
        defineTransition(S_TABLE, initial, S_COL, S_COL);
        defineTransition(S_TABLE, initial, S_COLGROUP, S_COLGROUP);
        defineTransition(S_TABLE, initial, S_THEAD, S_THEAD);
        defineTransition(S_TABLE, initial, S_TFOOT, S_TFOOT);
        defineTransition(S_TABLE, initial, S_TBODY, S_TBODY);
        defineTransition(S_TABLE, initial, S_TR, S_TR);
        defineMandatoryTransition(S_TABLE, initial, S_TR);

        // Transitions from the "caption" state
        defineTransition(S_TABLE, S_CAPTION, S_COL, S_COL);
        defineTransition(S_TABLE, S_CAPTION, S_COLGROUP, S_COLGROUP);
        defineTransition(S_TABLE, S_CAPTION, S_THEAD, S_THEAD);
        defineTransition(S_TABLE, S_CAPTION, S_TFOOT, S_TFOOT);
        defineTransition(S_TABLE, S_CAPTION, S_TBODY, S_TBODY);
        defineTransition(S_TABLE, S_CAPTION, S_TR, S_TR);
        defineMandatoryTransition(S_TABLE, S_CAPTION, S_TR);

        // Transitions from the "col" state
        defineTransition(S_TABLE, S_COL, S_COL, S_COL);
        defineTransition(S_TABLE, S_COL, S_THEAD, S_THEAD);
        defineTransition(S_TABLE, S_COL, S_TFOOT, S_TFOOT);
        defineTransition(S_TABLE, S_COL, S_TBODY, S_TBODY);
        defineTransition(S_TABLE, S_COL, S_TR, S_TR);
        defineMandatoryTransition(S_TABLE, S_COL, S_TR);

        // Transitions from the "colgroup" state
        defineTransition(S_TABLE, S_COLGROUP, S_COLGROUP, S_COLGROUP);
        defineTransition(S_TABLE, S_COLGROUP, S_THEAD, S_THEAD);
        defineTransition(S_TABLE, S_COLGROUP, S_TFOOT, S_TFOOT);
        defineTransition(S_TABLE, S_COLGROUP, S_TBODY, S_TBODY);
        defineTransition(S_TABLE, S_COLGROUP, S_TR, S_TR);
        defineMandatoryTransition(S_TABLE, S_COLGROUP, S_TR);

        // Transitions from the "thead" state
        defineTransition(S_TABLE, S_THEAD, S_TFOOT, S_TFOOT);
        defineTransition(S_TABLE, S_THEAD, S_TBODY, S_TBODY);
        defineTransition(S_TABLE, S_THEAD, S_TR, S_TR);
        defineMandatoryTransition(S_TABLE, S_THEAD, S_TR);

        // Transitions from the "tfoot" state
        defineTransition(S_TABLE, S_TFOOT, S_TBODY, S_TBODY);
        defineTransition(S_TABLE, S_TFOOT, S_TR, S_TR);
        defineMandatoryTransition(S_TABLE, S_TFOOT, S_TR);

        // Transitions from the "tbody" state
        defineTransition(S_TABLE, S_TBODY, S_TBODY, S_TBODY);

        // Transitions from the "tr" state
        defineTransition(S_TABLE, S_TR, S_TR, S_TR);
    }

    private void initTableCell(IParseKey key) {
        defineParent(key, S_TR);
        addFlow(key);
        if (useExtendedRules()) {
            // These additional transitions are defined to close an existing
            // table cell when an another "tr", "td" or "th" element is
            // occurred.
            IParseKey finalKey = getFINAL();
            defineTransition(key, S_TD, finalKey);
            defineTransition(key, S_TH, finalKey);
            defineTransition(key, S_TR, finalKey);
        }
    }

    private void initTableRowContainer(IParseKey key) {
        defineParent(key, S_TABLE);
        defineSubstates(key, S_TR);
        defineMandatoryTransition(key, getINITIAL(), S_TR);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_tbody
    // <!ELEMENT tbody (tr)+>
    protected void initTBODY() {
        initTableRowContainer(S_TBODY);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_td
    // <!ELEMENT td %Flow;>
    protected void initTD() {
        initTableCell(S_TD);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_textarea
    // <!ELEMENT textarea (#PCDATA)> <!-- multi-line text field -->
    protected void initTEXTAREA() {
        IParseKey parent = getDefaultFormElementContainer();
        defineParent(S_TEXTAREA, parent);
        addPCDATA(S_TEXTAREA);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_tfoot
    // <!ELEMENT tfoot (tr)+>
    protected void initTFOOT() {
        initTableRowContainer(S_TFOOT);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_th
    // <!ELEMENT th %Flow;>
    protected void initTH() {
        initTableCell(S_TH);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_thead
    // <!ELEMENT thead (tr)+>
    protected void initTHEAD() {
        initTableRowContainer(S_THEAD);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_title
    // <!ELEMENT title (#PCDATA)>
    protected void initTITLE() {
        defineParent(S_TITLE, S_HEAD);
        addPCDATA(S_TITLE);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_tr
    // <!ELEMENT tr (th|td)+>
    protected void initTR() {
        defineParent(S_TR, S_TABLE);
        defineSubstates(S_TR, S_TD, S_TH);
        defineMandatoryTransition(S_TR, getINITIAL(), S_TD);
        if (useExtendedRules()) {
            // Exit from the state when a new row is reported.
            // (It should create a new row in the same table and not create
            // a new embedded table);
            defineTransition(S_TR, S_TR, getFINAL());
        }
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_tt
    // <!ELEMENT tt %Inline;> <!-- fixed pitch font -->
    protected void initTT() {
        initPhraseItem(S_TT);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_ul
    // <!ELEMENT ul (li)+>
    protected void initUL() {
        initList(S_UL);
    }

    // http://www.w3.org/TR/xhtml1/dtds.html#dtdentry_xhtml1-strict.dtd_var
    // <!ELEMENT var %Inline;> <!-- variable -->
    protected void initVAR() {
        initPhraseItem(S_VAR);
    }

    protected boolean useExtendedRules() {
        return true;
    }
}